// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module net_comm_back_pkg 
(
    input  wire          I_sclk,
    input  wire          I_rst_n,
    //
    input  wire          I_net_rx_clk,
    input  wire          I_net_in_en,
    input  wire [ 7: 0]  I_net_in_data,
    // ram interface
    output reg  [ 10: 0] O_comm_back_ram_waddr,
    output reg  [ 7: 0]  O_comm_back_ram_wdata,
    output reg           O_comm_back_ram_wrreq,
    //
    input  wire          I_reg_clr_comm_back_flag,
    output reg           O_reg_rb_comm_back_flag,
    output wire          O_reg_rb_comm_back_crc_err,
    output reg  [ 11: 0] O_reg_rb_comm_back_length,
    //
    output reg           O_reg_reboot_to_test
);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam
    NET_HEAD_BYTES = 8,
    MIN_PKG_LENGTH = 128;
    
/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  [ 11: 0] net_in_cnt;
reg  fifo_wrreq;
reg  [ 7: 0] fifo_wdata;
reg  net_in_en_dly;
wire crc_err;
wire crc_check_complete;
reg  head_correct;
reg  is_comm_back_pkg;
reg  comm_back_pkg_finish;
reg  [ 3: 0] comm_back_pkg_finish_dly;
reg  comm_back_pkg_finish_extend;
wire comm_back_pkg_finish_sclk;
reg  comm_back_pkg_finish_sclk_dly;
wire reg_comm_back_flag;

/******************************************************************************
                                <module body>
******************************************************************************/
always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        net_in_en_dly <= 1'b0;
    else
        net_in_en_dly <= I_net_in_en;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        net_in_cnt <= 'd0;
    else if (!I_net_in_en || reg_comm_back_flag)
        net_in_cnt <= 'd0;
    else if (net_in_cnt != 12'hfff)
        net_in_cnt <= net_in_cnt + 1'b1;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        head_correct <= 1'b0;
    else if (!I_net_in_en)
        head_correct <= 1'b1;
    else if (net_in_cnt == NET_HEAD_BYTES - 2 && I_net_in_data != 8'h55)
        head_correct <= 1'b0;
    else if (net_in_cnt == NET_HEAD_BYTES - 1 && I_net_in_data != 8'hD5)
        head_correct <= 1'b0;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        is_comm_back_pkg <= 1'b0;
    else if (!I_net_in_en)
        is_comm_back_pkg <= 1'b0;
    else if (net_in_cnt == 52 - 1 && I_net_in_data == 8'hC0)
        is_comm_back_pkg <= 1'b1;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        O_comm_back_ram_wrreq <= 1'b0;
    else
        O_comm_back_ram_wrreq <= !reg_comm_back_flag && head_correct && I_net_in_en && net_in_cnt >= NET_HEAD_BYTES;

always @(posedge I_net_rx_clk)
    O_comm_back_ram_wdata <= I_net_in_data;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        O_comm_back_ram_waddr <= 'd0;
    else if (!O_comm_back_ram_wrreq)
        O_comm_back_ram_waddr <= 'd0;
    else if (O_comm_back_ram_waddr != 11'h7ff)
        O_comm_back_ram_waddr <= O_comm_back_ram_waddr + 1'b1;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        O_reg_rb_comm_back_length <= 'd0;
    else if (net_in_en_dly && !I_net_in_en)
        O_reg_rb_comm_back_length <= net_in_cnt - NET_HEAD_BYTES - 4;

//crc_check u_crc_check
//(
//    .I_sclk(I_net_rx_clk),
//    .I_rst_n(I_rst_n),
//    .I_net_en(I_net_in_en && !reg_comm_back_flag),
//    .I_net_data(I_net_in_data),
//    .O_error(crc_err),
//    .O_crc_check_complete(crc_check_complete)
//);

assign O_reg_rb_comm_back_crc_err = 1'b0;
//always @(posedge I_net_rx_clk or negedge I_rst_n)
//    if (!I_rst_n)
//        O_reg_rb_comm_back_crc_err <= 1'b0;
//    else if (crc_check_complete)
//        O_reg_rb_comm_back_crc_err <= crc_err;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        comm_back_pkg_finish <= 1'b0;
    else if (comm_back_pkg_finish)
        comm_back_pkg_finish <= 1'b0;
    else if (net_in_en_dly && !I_net_in_en && net_in_cnt > MIN_PKG_LENGTH && head_correct && is_comm_back_pkg)
        comm_back_pkg_finish <= 1'b1;

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        comm_back_pkg_finish_dly <= 8'b0;
    else
        comm_back_pkg_finish_dly <= {comm_back_pkg_finish_dly[2:0],comm_back_pkg_finish};

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        comm_back_pkg_finish_extend <= 1'b0;
    else if (comm_back_pkg_finish_dly != 'd0)
        comm_back_pkg_finish_extend <= 1'b1;
    else
        comm_back_pkg_finish_extend <= 1'b0;

sync_cell
#(
    .RESET_VALUE(0)
)
u_sync_reg_comm_back_flag
(
    .I_clk(I_net_rx_clk),
    .I_rst_n(I_rst_n),
    .I_data_in(O_reg_rb_comm_back_flag),
    .O_data_out(reg_comm_back_flag)
);

//--------------------------------------------------------------------
// I_sclk clock domain
//--------------------------------------------------------------------
sync_cell
#(
    .RESET_VALUE(0)
)
u_sync_comm_back_pkg_finish
(
    .I_clk(I_sclk),
    .I_rst_n(I_rst_n),
    .I_data_in(comm_back_pkg_finish_extend),
    .O_data_out(comm_back_pkg_finish_sclk)
);

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        comm_back_pkg_finish_sclk_dly <= 1'b0;
    else
        comm_back_pkg_finish_sclk_dly <= comm_back_pkg_finish_sclk;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_reg_rb_comm_back_flag <= 1'b0;
    else if (I_reg_clr_comm_back_flag)
        O_reg_rb_comm_back_flag <= 1'b0;
    else if (!comm_back_pkg_finish_sclk_dly && comm_back_pkg_finish_sclk)
        O_reg_rb_comm_back_flag <= 1'b1;

//--------------------------------------------------------------------
// reboot_to_test
//--------------------------------------------------------------------
reg  reboot_rx_clk;
wire reboot_sclk;
reg  reboot_sclk_dly;
reg  [ 7: 0] net_in_data_dly1;
reg  [ 7: 0] net_in_data_dly2;

always @(posedge I_net_rx_clk)
    begin
    net_in_data_dly1 <= I_net_in_data;
    net_in_data_dly2 <= net_in_data_dly1;
    end

always @(posedge I_net_rx_clk or negedge I_rst_n)
    if (!I_rst_n)
        reboot_rx_clk <= 1'b0;
    else if (!I_net_in_en)
        reboot_rx_clk <= 1'b0;
    else if (!head_correct)
        reboot_rx_clk <= 1'b0;
    else if (net_in_cnt == 52 - 1 && I_net_in_data == 8'hED && net_in_data_dly1 == 8'hAB && net_in_data_dly2 == 8'hBA)
        reboot_rx_clk <= 1'b1;
    else if (net_in_cnt == 53 - 1 && I_net_in_data == 8'hCC && reboot_rx_clk)
        reboot_rx_clk <= 1'b1;
    else
        reboot_rx_clk <= 1'b0;

sync_cell
#(
    .RESET_VALUE(0)
)
u_sync_reboot_rx_clk
(
    .I_clk(I_sclk),
    .I_rst_n(I_rst_n),
    .I_data_in(reboot_rx_clk),
    .O_data_out(reboot_sclk)
);

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        reboot_sclk_dly <= 1'b0;
    else
        reboot_sclk_dly <= reboot_sclk;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_reg_reboot_to_test <= 1'b0;
    else if (O_reg_reboot_to_test)
        O_reg_reboot_to_test <= 1'b0;
    else if (!reboot_sclk_dly && reboot_sclk)
        O_reg_reboot_to_test <= 1'b1;
 

endmodule
`default_nettype wire

